package com.csw.android.dev_utils.ui

import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * ## Fragment 视图属性，用于fragment属性代理，被代理的变量将跟随fragment的视图生命周期，当视图销毁时，变量自动置空，防止内存泄露
 *
 * ### 使用场景：
 * fragment 属于碎片化页面，意在可以自由组合用于显示，但页面中有的fragment可能暂时处于不可见状态，若继续持有视图
 * 会造成资源浪费，所以视图只是fragment生命周期中需要显示时创建，不需要显示时进行销毁的附加产物。
 *
 * 举个例子：拥有几百个页面的fragmentViewPager，几百个fragment都持有视图与当前显示和预缓冲的那几个fragment持有
 * 视图在内存占用上是一个非常大的差距，所以正常的使用方式是fragment保留数据，在需要的时候利用数据重新创建视图用于显示。
 *
 * 为了保证视图或者其它与视图配合的对象被及时释放，使用此类进行属性代理，即可不用每次onDestroyView都需要手动置空。
 * 例如fragment中包含的adapter（->recyclerView->parent->rootView）等属性，每次创建视图都会重新创建，若不在视图销毁时置空，将会一直持有视图。
 *
 * @param onValueDestroy 引用对象被回收前会通过此方法回调告知外部进行首尾处理，可以在此方法回调时进行资源释放等操作
 */
class FragmentViewProperty<V>(private val onValueDestroy: ((V?) -> Unit)? = null) :
    ReadWriteProperty<Fragment, V?> {

    /**真实存储的变量值*/
    private var realValue: V? = null

    /**视图状态追踪，视图销毁时自动置空变量值*/
    private lateinit var fragmentViewStateTracker: FragmentViewStateTracker

    /**确保fragmentViewStateTracker实例不为空*/
    private fun ensureFragmentViewStateTracker(fragment: Fragment): FragmentViewStateTracker {
        if (!this::fragmentViewStateTracker.isInitialized) {
            fragmentViewStateTracker = FragmentViewStateTracker(fragment)
        }
        return fragmentViewStateTracker
    }

    /**
     * 变量赋值，为防止内存泄露，置空操作可以在任意时刻进行，但赋值操作只能在视图创建之后进行
     *
     * @param thisRef 被代理变量所在的类
     * @param property 被代理变量签名
     * @param value 想要设置的新值
     */
    override fun setValue(thisRef: Fragment, property: KProperty<*>, value: V?) {
        if (value == null || ensureFragmentViewStateTracker(thisRef).isViewCreated()) {
            realValue = value
        } else {
            throw RuntimeException("为防止被代理属性（${property.name}）出现内存泄露，请在视图创建之后再进行赋值")
        }
    }

    override fun getValue(thisRef: Fragment, property: KProperty<*>): V? {
        ensureFragmentViewStateTracker(thisRef)
        return realValue
    }

    /**
     * Fragment视图状态追踪器
     */
    private inner class FragmentViewStateTracker(fragment: Fragment) {
        /**视图生命周期，当新的生命周期对象被创建时，重新订阅*/
        private var viewLifecycleOwner: LifecycleOwner? = null
            set(value) {
                if (field === value) {
                    return
                }
                field?.lifecycle?.removeObserver(viewLifecycleListener)
                field = value
                field?.lifecycle?.addObserver(viewLifecycleListener)
            }

        /**视图生命周期监听*/
        private val viewLifecycleListener = LifecycleEventObserver { _, event ->
            //在视图销毁时，将属性置空，释放引用
            if (event.targetState == Lifecycle.State.DESTROYED) {
                onValueDestroy?.invoke(realValue)
                realValue = null
            }
        }

        init {
            //初始化时添加视图生命周期监听，由于fragment的viewLifecycleOwner在每次创建视图的时候都会刷新，这里
            // 通过liveData进行订阅
            fragment.viewLifecycleOwnerLiveData.observeForever {
                viewLifecycleOwner = it
            }
        }

        /**
         * ### 判断视图是否已经创建
         *
         * 由于Fragment先进行视图创建，然后创建viewLifecycleOwner(INITIALIZED)，
         * 然后回调onViewCreated，然后再分发状态使viewLifecycleOwner过渡到CREATED.STARTED.RESUMED等，所以
         * 这里viewLifecycleOwner的生命周期至少在INITIALIZED之上即认为视图已经存在
         */
        fun isViewCreated() =
            viewLifecycleOwner?.lifecycle?.currentState?.isAtLeast(Lifecycle.State.INITIALIZED) == true
    }
}